﻿using Application.Commons.Data;
using AutoMapper;
using Domain.Entities.Modulers;
using FrameworkCore.Constants;
using FrameworkCore.Extensions;
using FrameworkCore.Helpers;
using FrameworkCore.Models;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;

namespace NM.Module.Manager.API.Commands.Upload;

#nullable disable

/// <summary>
/// 上传模块
/// </summary>
public class UploadModulerCommand : IRequest<Result<bool>>
{
    /// <summary>
    /// 模块文件
    /// </summary>
    public IFormFile ModuleFile { get; set; }
}

/// <summary>
/// 处理程序
/// </summary>
public class UploadModulerCommandHandler : IRequestHandler<UploadModulerCommand, Result<bool>>
{
    private readonly ApplicationDbContext _context;
    private readonly IMapper _mapper;
    public UploadModulerCommandHandler(ApplicationDbContext context, IMapper mapper)
    {
        _context = context;
        _mapper = mapper;
    }

    public async Task<Result<bool>> Handle(UploadModulerCommand request, CancellationToken cancellationToken)
    {
        ExceptionHelper.ThrowIfNull(request.ModuleFile, "上传的文件无效");

        var uploadPath = ApplicationPartManagerExtensions
            .GetModulesDirectory(ConfigurationsExtensions.GetGlobalSection<List<string>>(GlobalConstants.UploadPathsKey));

        Directory.CreateDirectory(uploadPath);

        var fileName = request.ModuleFile.FileName;
        var savePath = Path.Combine(uploadPath);
        var fullPath = Path.Combine(savePath, fileName);
        var fileExtension = Path.GetExtension(fullPath);
        var modulerLibrary = new ModulerLibrary();
        modulerLibrary.Name = fileName;

        ExceptionHelper.ThrowIfFalse(fileExtension == GlobalConstants.NugetPackageSuffix, "上传的文件无效");

        Directory.CreateDirectory(savePath);

        // 将文件保存到磁盘，存在则覆盖
        using (var stream = new FileStream(fullPath, FileMode.Create))
        {
            await request.ModuleFile.CopyToAsync(stream);
        }

        string tempDirectory = ApplicationPartManagerExtensions.ExtractPackage(fullPath, uploadPath);

        Match matchVersion = Regex.Match(fileName, GlobalConstants.VersionRegex);
        ExceptionHelper.ThrowIfFalse(matchVersion.Success, "版本号规则错误");

        modulerLibrary.Version = matchVersion.Value;
        Directory.EnumerateFiles(tempDirectory, "*.xml", SearchOption.AllDirectories).ToList().ForEach(file =>
        {
            fileName = $"{fileName.Replace(modulerLibrary.Version, "").Replace(".nupkg", "")}";
            if (file.Contains($"{fileName}xml"))
            {
                var reader = XmlReader.Create(file);
                using (reader)
                {
                    var xmlDoc = XDocument.Load(reader);
                    var node = xmlDoc.Root.Element("members").Elements("member")
                        .LastOrDefault(n => n.Attribute("name").Value.StartsWith($"T:{fileName}") && n.Attribute("name").Value.EndsWith("Startup"));
                    modulerLibrary.Title = node?.Element("summary")?.Value.Trim();
                }
            }
        });

        Directory.Delete(tempDirectory, true);

        var moduler =await _context.ModulerLibraries.SingleOrDefaultAsync(x => x.Name == modulerLibrary.Name);
        if (moduler == null)
        {
            await _context.ModulerLibraries.AddAsync(modulerLibrary);
        }
        else 
        {
            moduler.Title = modulerLibrary.Title;
            moduler.Name = modulerLibrary.Name;
            moduler.Version = modulerLibrary.Version;

            _context.ModulerLibraries.Update(moduler);
        }

        var result = (await _context.SaveChangesAsync()) > 0;
        ExceptionHelper.ThrowIfFalse(result, "上传模块失败");

        return await Result<bool>.SucceedAsync(true);
    }
}